#include "GameEngine.h"



GameEngine::GameEngine()
{
    charCon.getCharacter()->setPosition(GS->getStartPosition().cast<float>());
    physEng.addRigidBody(charCon.getCharacter());

    //factory.addDoor(vector3<int>(128,1,128));
    //factory.addSwitch(vector3<int>(128,1,140));
    //factory.addSpikes(vector3<int>(128,1,130));
    //factory.addLadder(vector3<int>(128,1,100));
    //factory.addEnemy(vector3<int>(128,1,80));
    //ElementSwitch* s = factory.getSwitch(vector3<int>(128,1,140));
    //s->addTarget(factory.getDoor(vector3<int>(128,1,128)));
    //s->addTarget(factory.getSpikes(vector3<int>(128,1,130)));
    //s=0;
}

GameEngine* GameEngine::getInstance(){
    static GameEngine* inst=0;
    if(inst) return inst;
    else return inst=new GameEngine();
}

void GameEngine::editorRender(){
    MAP_TYPE &c = factory.getCollection();

    for(MAP_TYPE::iterator i = c.begin(); i!=c.end();i++)
        (*i).second->editorModeRender();
}

void GameEngine::render(){
    if(checkEndGameCondition()) resetGame();
    for(int i=0;i<elements.size();i++)
        elements[i]->render();
    update();
    charCon.invokeCharRender();

}

void GameEngine::renderOverlay(){
    glPushMatrix();
    glDisable(GL_LIGHTING);
    glColor3f(0,0.7,0);
    Drawing::drawBox(10,10,charCon.getCharacter()->getHP(),30);
    glColor3f(0,0,0);
    Drawing::drawBoxWithoutFill(9,9,charCon.getCharacter()->getMaxHP()+1,31);
    glEnable(GL_LIGHTING);
    glPopMatrix();
}


void GameEngine::invokeCollisionEvent(){
    for(int i=0;i<elements.size();i++){
        if(Collision::hasCollidedWithBodyAtOffset( *charCon.getCharacter() , *elements[i], GE_BODY_OFFSET ))
           elements[i]->invokeCollisionEvent(charCon.getCharacter());

    }
}

void GameEngine::invokeActivateEvent(){
    vector3<float> front = vector3<float>(REND->Camera.getLookAtVector().x,0,REND->Camera.getLookAtVector().z).unit();


    AABB temp = charCon.getCharacter()->geometry;
    temp.translate(front*ACTIVATE_EVENT_EPSILON);
    for(int i=0;i<elements.size();i++){
        if(charCon.getCharacter()->geometry.hasContactedAABB(elements[i]->geometry) ||
           temp.hasContactedAABB(elements[i]->geometry))
           elements[i]->invokeActivateEvent();
    }

}

void GameEngine::invokeUpdateEvent(){
    for(int i=0;i<elements.size();i++)
        elements[i]->invokeUpdateEvent(charCon.getCharacter());
}

void GameEngine::update(){

    invokeCollisionEvent();
    invokeUpdateEvent();
    physEng.update();


}

void GameEngine::compileElements(){
    MAP_TYPE& arr=factory.getCollection();
    elements.reset();
    physEng.clearAllBodies();
    physEng.addRigidBody(charCon.getCharacter());
    for(MAP_TYPE::iterator i=arr.begin();i!=arr.end();i++){
        GameElement* temp = (*i).second;
        elements.push(temp);
        if(temp->isCollidable || temp->isDynamic)physEng.addRigidBody(temp);
    }
}

void GameEngine::initSession(){
    compileElements();
}

void GameEngine::resetSession(){
    for(int i=0;i<elements.size();i++)
    {
        if(elements[i]->getType()==ENEMY)
        {
            dynamic_cast<ElementEnemy*>(elements[i])->resetPostion();
        }
    }
}

void GameEngine::resetGame()
{
    resetSession();
    initSession();
    charCon.getCharacter()->setPosition(GS->getStartPosition().cast<float>());
    charCon.getCharacter()->s.velocity=vector3<float>(0,0,0);
    charCon.getCharacter()->setHP(charCon.getCharacter()->getMaxHP());
}

bool GameEngine::checkEndGameCondition()
{
    return (charCon.getCharacter()->getHP()==0);
}
